/**
 * 
 */
package controller.main;

import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import model.DbAccess.ConnectionManager;
import model.dao.CountryDao;
import model.dto.Location;
import model.service.ChubJobs;
import model.service.FtpController;
import model.service.LoggerController;
import model.service.SchedulerTask;
import model.service.threads.CountryThread;
/**
 * @author samy.a.omar
 *
 */
public class Executer {

	//public static final String PROPERTY_FILE_PATH="/controller/DBconfiguration.properties";
	


	static Logger logger = Logger.getLogger(Executer.class);
	
	static List<Location> locations=new ArrayList<Location>();
	
/*
 * Note that the method you show does unnecessary work by loading logger configuration - 
 * this is done automatically by Log4J if you name your config file log4j.properties
 * 
 * 
 * */
	
	/**
	 * @param args
	 * first parameter will be the operation name
	 * second parameter will be the country name
	 * 
	 */
	
	public static void main(String[] args) {
		
		
	
		logger.info("Begin ..!!!");
		Connection conn = null ;
		try {
			
			PropertyConfigurator.configure(new FileInputStream(getJarDirectory()+File.separator+"log4j.properties")); // called only once in the application
			
			/*
			 * I have to separate the FTP from Loading
			 * So if the app is going to FTP only so oppening a connection on DB is not a must
			 * and should continue working
			 * also the main should accept parameters like loading_type
			 * and
			 * 
			 * Optional we will add args[2] which is  the interface name (INVOICE, STOCK)
			 * 
			 * 
			 * */
			
			// 1- validate and prepare the passed parameters
			// 2- get the list of countries and list of interfaces
			// 3- call execute function to begin the race			
			
			//PropertyConfigurator.configure("/home/hend/chub-executer/cronlog4j.properties");
			//PropertyConfigurator.configure("C:\\Documents and Settings\\samy.a.omar\\workspace_3_7_2\\chub-executer\\src\\controller\\cronlog4j.properties");
			//PropertyConfigurator.configure("E:\\workspace\\chub-executer\\cronlog4j.properties");
			
		//	return ;
			
			
			//ConnectionManager connManger = new ConnectionManager();
		//	conn = connManger.getConnection();
		//	/
				
			
			//new SchedulerTask(); /*hashed by Samy*/
			
	//		args = new String[3];
	//		args[0] = Constants.ALL;
	//		args[1] = "JOR,IRQ,LEB,PAL,SYR,SUD,KSA,KWT,QTR"  ;//,IRQ
	//		args[2] = "stock,invoice,cust_master,salesman,sales_order"  ; //,invoice
			
			String operation = "" ;
			String country   =   "" ;
			String interfaceName   =   "" ;
			
			ChubJobs chubJobs = new ChubJobs();
			//System.out.println(args[0]);
			//System.out.println(args[1]);
			
			/*if(args[0].equals(Constants.FTP_PROCESS))
			{
				System.out.println("ddsdsdsd");	
			}*/
						
			
			if(args ==null || args.length ==0)
			{
				operation = Constants.ALL ;
				country = Constants.ALL ;
				interfaceName = Constants.ALL ;
			}
			else if (!args[0].equals(Constants.FTP) && !args[0].equals(Constants.PROCESS) && !args[0].equals(Constants.MAIL) 
					 && !args[0].equals(Constants.FTP_PROCESS) && !args[0].equals(Constants.PROCESS_MAIL) && !args[0].equals(Constants.ARCHIVE) && !args[0].equals(Constants.ALL) )
			{
				System.out.println(args[0] + " is an invlid operation name.");	 
				return ;
			}
			else if(args[1]== null || args[1].equals("ALL") || args[1].trim().equals(""))
			{
				operation = args[0] ;
				country = Constants.ALL ;
			}
			else if(args[2]== null || args[2].equals("ALL") || args[2].trim().equals(""))
			{
				operation = args[0] ;
				country = Constants.ALL ;
				interfaceName = Constants.ALL ;
			}
			else
			{
				operation = args[0] ;
				country = args[1] ;
				interfaceName = args[2] ;
			}
            //////////////////////////////
			List countries = null ;
			List interfaces = null ;
			
			if (!country.equals(Constants.ALL) && country != null) {
				 countries =  getCountriesList(country);	
			}
			if (!interfaceName.equals(Constants.ALL) && interfaceName != null) {
				interfaces =  getInterfacesList(interfaceName);	
			}
			
			
			if(args[0].equals(Constants.ARCHIVE))
			{
					chubJobs.archive(countries, interfaces);
					return;
			}

			executer(operation,countries,interfaces);
			System.out.println("Done !!");
			logger.info("Done !!");
			
		} catch (Exception e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
			logger.info("Cron Failed..!!!");
		}
		finally{
			try {
				if(conn!=null && !conn.isClosed())
				{
					conn.close();
					
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/*
	 * This method is 100% thread safe, it would be even if it wasn't static. 
		he problem with thread-safety arises when you need to share data between threads - 
			 * you must take care of atomicity, visibility, etc.
		This method only operates on parameters, which reside on stack and references to 
		immutable objects on heap. Stack is inherently local to the thread, so no sharing of data occurs, ever.
		Immutable objects (String in this case) are also thread-safe because once created 
		they can't be changed and all threads see the same value. On the other 
		hand if the method was accepting (mutable) Date you could have had a problem. 
		Two threads can simultaneously modify that same object instance, 
		causing race conditions and visibility problems.
	 * */
	public static void executer(String operation , List countries ,List interfaces )
	{

	// 1- run thread for every country passing the operation and interfaces parameter
	// 2- wait until all threads get finished then return

		ArrayList<Thread> threads = new ArrayList<Thread>();
		
		for (int i=0;i<countries.size() ;i++)
		{
			String country = (String)countries.get(i);			
			Runnable task=new CountryThread(operation,country,interfaces);
			Thread worker = new Thread(task);
			worker.setName("Thread "+i);
			worker.start();
			threads.add(worker);
		}
		
		int running = 0;
		do {
			running = 0;
			for (Thread thread : threads) {
				if (thread.isAlive()) {
					running++;
				//	System.out.println(thread.getName());
				}
			}
			//System.out.println("We have " + running + " running threads. ");
		} while (running > 0);
		System.out.println("All threads has been finished.");
		
		//Country countries[] = getCountriesInfo(args[0] , args[1]);
		// loop over args and decide which countries to FTP
		
		//System.out.println("calling getCountriesInfo");
		
		//locations=getCountriesInfo(country);
		
		//System.out.println("loading");
		//System.out.println(locations);
		
		//loading(operation,locations);
		
		 // Ftp files, sending parameters of country Or ALL
		// call DB to process files 
		
	}
	
	
	public static List<Location> getCountriesInfo(String country)
	{

		CountryDao cd=new CountryDao();
		locations=cd.getCountryLocations(country);
		System.out.println(locations);
		return locations;
		
	}
	
		public static void loading(String loadingType,List<Location> locations)
		{
			FtpController ftpController=new FtpController();
			ftpController.FTPFilesToLocalRepository(locations,loadingType);
			
			/*if(loadingType.equalsIgnoreCase(FTP))
			{
				//call ftp(loc);
				FtpController ftpController=new FtpController();
				ftpController.FTPFilesToLocalRepository(locations);
			}
			else if(loadingType.equalsIgnoreCase(FTP_LOAD))
			{
				//call ftp +database methods
				FtpController ftpController=new FtpController();
				ftpController.FTPFilesToLocalRepository(locations);
			}
			else if(loadingType.equalsIgnoreCase(LOAD))
			{
				//cal database function;
			}*/
			
		}
	
		
		

		public static List getCountriesList(String countries)
		{
			String[] countriesArray = countries.split(",");
			return StringArrayToStringList(countriesArray);
		}
		
		public static List getInterfacesList(String interfaces)
		{
			String[] interfacesArray = interfaces.split(",");
			return StringArrayToStringList(interfacesArray);
		}
		
		public static List StringArrayToStringList(String[] stringArray)
		{
			List stringList = new ArrayList();
			for (int i = 0; i < stringArray.length; i++) {
				stringList.add(stringArray[i]) ;	
			}
			return stringList ;
		}
		
		
		
		public static String getJarDirectory() 
		{
			
			
			String path = Executer.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			logger.info("Path of the class " + path );
		    String decodedPath;
		    String jarDir = "" ;
			try 
			{
				
				decodedPath = URLDecoder.decode(path, "UTF-8");
				logger.info("Path of the class after decoding " + decodedPath);
				
			    File jarFile = new File(decodedPath);
			    logger.info("The file jarFile is " + jarFile );
			    jarDir = jarFile.getParentFile().getPath();
			    logger.info("The file jarFile path " + jarDir  );
			    
			    
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception ex)
			{
				ex.printStackTrace();
				logger.info(ex.getMessage());
				//throw ex ;
			}
		    return jarDir ;
		}
		
		
		

}
